<template>
  <div>
    <!-- 导入数据 那些列, 脱敏, 类型推断, 语义推断 -->
    <div v-if="uploadType === 'table'" class="import-data-set">
      <div class="data-set-column">
        <a-form-item
          label="数据类型"
          :label-align="'left'"
          :label-col="{ span: 6 }"
        >
          <a-radio-group v-model="tableDataGisType">
            <a-radio value="point">点数据</a-radio>
            <a-radio value="region">面数据</a-radio>
          </a-radio-group>
        </a-form-item>
      </div>
      <div
        v-if="tableDataGisType === 'point'"
        class="data-set-column"
        style="width: 250px;"
      >
        <a-form-item
          label="字段类型"
          :label-align="'left'"
          :label-col="{ span: 8 }"
          :wrapper-col="{ span: 10 }"
        >
          <a-select v-model="columnGisType" size="small">
            <a-select-option value="latlng">经纬度</a-select-option>
            <a-select-option value="region">行政区</a-select-option>
          </a-select>
        </a-form-item>
        <!-- <a-form-item
          label="脱敏设置"
          :label-align="'left'"
          :label-col="{ span: 5 }"
        >
          <div class="desensitization-set">
            <a-button
              class="data-setting-button"
              type="link"
              @click="DesensitizationSetModalVisible = true"
            >
              <a-icon-font
                class="icon-font"
                type="iconzidingyi"
                style="color: #5561ff;"
              />
              <span>设置</span>
            </a-button>
            <a-checkbox
              :checked="isDataTypeInfer"
              style="margin-left: 17px;"
              @change="changeTypeInfer"
            >
              推断类型
            </a-checkbox>
            <a-checkbox
              :checked="isDataSemanticInfer"
              @change="changeSemanticInfer"
            >
              推断语义
            </a-checkbox>
          </div>
        </a-form-item> -->
      </div>
      <template v-if="isShowLatLngField">
        <div class="data-set-column" style="width: 200px;">
          <a-form-item
            label="经度"
            :label-align="'left'"
            :label-col="{ span: 6 }"
            :wrapper-col="{ span: 10 }"
          >
            <a-select v-model="lonCol" size="small">
              <a-select-option
                v-for="list in getSemanticColumnList(['longitude'])"
                :key="list.name"
                :value="list.name"
                >{{ list.name }}</a-select-option
              >
            </a-select>
          </a-form-item>
        </div>
        <div class="data-set-column" style="width: 200px;">
          <a-form-item
            label="纬度"
            :label-align="'left'"
            :label-col="{ span: 6 }"
            :wrapper-col="{ span: 10 }"
          >
            <a-select v-model="latCol" size="small">
              <a-select-option
                v-for="list in getSemanticColumnList(['latitude'])"
                :key="list.name"
                :value="list.name"
                >{{ list.name }}</a-select-option
              >
            </a-select>
          </a-form-item>
        </div>
      </template>
      <div v-if="isShowCityField" class="data-set-column">
        <a-form-item
          label="行政区"
          :label-align="'left'"
          :label-col="{ span: 8 }"
          :wrapper-col="{ span: 10 }"
        >
          <a-select v-model="regionCol" size="small">
            <a-select-option
              v-for="list in getSemanticColumnList(['city', 'province'])"
              :key="list.name"
              :value="list.name"
              >{{ list.name }}</a-select-option
            >
          </a-select>
        </a-form-item>
      </div>
    </div>
    <!-- gis 导入预览 确认按钮 -->
    <a-spin :spinning="tablePreviewMask">
      <!-- gis 表格文件 excel csv 导入 -->
      <template
        v-if="
          previewDataWithTypeSemantic && previewDataWithTypeSemantic.length > 0
        "
      >
        <!-- 多表 -->
        <a-tabs
          v-if="previewDataWithTypeSemantic.length > 1"
          type="card"
          :default-active-key="
            previewDataWithTypeSemantic &&
            previewDataWithTypeSemantic.length > 0
              ? previewDataWithTypeSemantic[0].fileName
              : null
          "
          @change="changeTable"
        >
          <a-tab-pane
            v-for="table in previewDataWithTypeSemantic"
            :key="table.fileName"
            :tab="table.name"
          >
            <data-preview-table
              :head="table.head"
              :data="table.data"
              data-type="table"
              @changeColType="changeColType"
              @change-semantic="changeSemantic"
            />
          </a-tab-pane>
        </a-tabs>
        <!-- 单表 -->
        <data-preview-table
          v-else
          :head="previewDataWithTypeSemantic[0].head"
          :data="previewDataWithTypeSemantic[0].data"
          data-type="table"
          @changeColType="changeColType"
          @change-semantic="changeSemantic"
        />
      </template>
      <div class="button-container">
        <a-button @click="cancelImportData">取消</a-button>
        <a-button
          :loading="loading"
          type="primary"
          class="button"
          @click="handleSubmit"
          >确定</a-button
        >
      </div>
    </a-spin>
    <!-- 脱敏弹窗 -->
    <desensitization-set-modal
      :visible="DesensitizationSetModalVisible"
      :have-set-desensitization="haveSetDesensitization"
      @cancel="DesensitizationSetModalVisible = false"
      @config-submit="configSettingSubmit"
    />
  </div>
</template>

<script lang="ts">
/**
 * gis 数据信息 分离
 * @author
 */
import { Component, Vue, Watch } from 'vue-property-decorator'
import GisDataStore from '@/store/modules/gis-data'
import DataStore from '@/store/modules/data'
import DataPreviewTable from '@/components/data/DatasetPreviewTable.vue'
import { cloneDeep, intersection, uniq } from 'lodash'
import DesensitizationSetModal from '@/components/data/gis/DesensitizationSetModal.vue'

@Component({
  components: {
    DataPreviewTable,
    DesensitizationSetModal,
  },
})
export default class GisDataInfo extends Vue {
  // 批次号
  private get batch(): string {
    return GisDataStore.batch
  }
  // 上传类型
  public get uploadType(): string {
    return GisDataStore.uploadType
  }
  // 文件类型：csv, excel （上传类型-表格）
  public get uploadTypeTableFileType(): string {
    return GisDataStore.uploadTypeTableFileType
  }
  // 编码格式
  private get codingType(): string {
    return GisDataStore.codingType
  }
  // 数据集名称
  public get datasetName(): string {
    return GisDataStore.datasetName
  }
  // 将第一行作为数据表的列字段名称  (上传类型 table)
  public get firstLineAsFields() {
    return GisDataStore.firstLineAsFields
  }

  // 传入预览表的数据（表格文件 导入 数据预览数据
  public get previewData(): any {
    return GisDataStore.previewData
  }

  /**
   * gis分类 category id
   */
  private get gisDataCategory() {
    return DataStore.datasetCategory.filter((item) =>
      item.categoryName.includes('我的GIS文件')
    )[0]?.categoryId
  }

  /**
   * 显示经纬度字段
   */
  private get isShowLatLngField() {
    return this.tableDataGisType === 'point' && this.columnGisType === 'latlng'
  }

  /**
   * 显示行政区字段
   */
  private get isShowCityField() {
    return (
      (this.tableDataGisType === 'point' && this.columnGisType === 'region') ||
      this.tableDataGisType === 'region'
    )
  }

  /**
   * 当前表的字段List
   */
  private get columnList(): {
    name: string
    type: string
    semantic: string
  }[] {
    const index =
      this.previewDataWithTypeSemantic.length > 0
        ? this.previewDataWithTypeSemantic.findIndex(
            (item: any) => item.fileName === this.activeTableFileName
          )
        : 0
    return this.previewDataWithTypeSemantic[index].head
  }

  /**
   * 筛选特定语义的字段
   */
  private getSemanticColumnList(semanticList: string[]) {
    if (Array.isArray(semanticList) && semanticList.length > 0) {
      return this.columnList.filter((column) => {
        return semanticList.includes(column.semantic)
      })
    }
    return this.columnList
  }

  // 已设置的脱敏设置  与导入设置 （如果为多个表， 会存储多个表的设置）
  public haveSetDesensitization: any = {}
  public DesensitizationSetModalVisible: boolean = false // 脱敏 Modal 显示
  private isDataTypeInfer: boolean = true // 是否类型推断
  private isDataSemanticInfer: boolean = true // 是否语义推断
  public previewDataWithTypeSemantic: any = null // 预览数据 附带 数据类型 语义
  public loading: boolean = false

  public tablePreviewMask: boolean = false // loading
  private tableDataGisType: 'point' | 'region' = 'point' // table数据导入的gis类型
  private columnGisType: 'latlng' | 'region' = 'latlng' // 字段类型
  private latCol: string = '' // 纬度字段
  private lonCol: string = '' // 经度字段
  private regionCol: string = '' // 行政区字段

  // 监听数据导入新的表
  @Watch('previewData', { deep: true, immediate: true })
  public watchPreviewData(data: any) {
    if (data) {
      this.previewDataWithTypeSemantic = cloneDeep(this.previewData)
      this.activeTableFileName = this.previewDataWithTypeSemantic[0].fileName
      this.initDesensitizationList(this.previewDataWithTypeSemantic)
      this.changePreviewDataSemantic(true)
    } else {
      this.clearInfo() // 预览数据清空
    }
  }

  /**
   * 清除状态
   * 使用：预览数据清空， 切换上传类型， 取消上传
   */
  public clearInfo() {
    this.previewDataWithTypeSemantic = null
    this.haveSetDesensitization = {}
  }

  /**
   * 初始化 脱敏列表 默认 全部字段（列） 导入 不脱敏, 多张表 中字段（列）是都导入 是否脱敏 脱敏类型 脱敏方式
   * {
   *   tableName: { columnName: {dataLevelId: 脱敏类型, dataMaskingType: 'md5', importColumn: 是否导入, masking: 脱敏}  }
   * }
   * @param tables
   * @author
   */
  public initDesensitizationList(tables: any) {
    const setDesensitization: any = cloneDeep(this.haveSetDesensitization) // 历史脱敏配置的备份
    this.haveSetDesensitization = {} // init
    if (tables) {
      tables.forEach((table: any) => {
        let columnMap: any = {} // 每张表对应的脱敏配置
        // 历史脱敏配置中是否有当前表
        if (!setDesensitization[table.tableName]) {
          table.head.forEach((column: any) => {
            if (typeof column === 'string') {
              columnMap[column] = {
                dataLevelId: 1,
                dataMaskingType: 'md5',
                importColumn: true,
                masking: false,
              } // 外部数据库
            } else {
              columnMap[column.name] = {
                dataLevelId: 1,
                dataMaskingType: 'md5',
                importColumn: true,
                masking: false,
              } // 本地文件上传
            }
          })
        } else {
          // 应对 当选择两张表， 且脱敏信息都已经配置， 删除一个， 则另一个在初始化的时候保留上次配置
          columnMap = setDesensitization[table.tableName]
        }
        this.haveSetDesensitization[table.name] = columnMap // 本地文件上传
      })
    } else {
      this.haveSetDesensitization = {}
    }
  }

  /**
   * 取消导入
   */
  public cancelImportData() {
    this.clearInfo()
    if (this.uploadType === 'shapefile') {
      GisDataStore.updateBatchNumber() // 更新批次号
    } else if (this.uploadType === 'table') {
      GisDataStore.setUploadTypeTableFileType('')
    }
  }

  /**
   * 修改完成脱敏配置
   */
  public configSettingSubmit(data: any) {
    this.haveSetDesensitization = data.desensitization
    this.DesensitizationSetModalVisible = false
    this.getDataWithMask()
  }

  /**
   * 脱敏设置后更新数据预览(当前表的预览数据)
   */
  public getDataWithMask() {
    const maskData: any = []
    const tableNames = Object.keys(this.haveSetDesensitization)
    const fileNames: any = []
    this.previewDataWithTypeSemantic.forEach((element: any) => {
      fileNames.push(element.fileName)
    })
    const index =
      this.previewDataWithTypeSemantic.length > 0
        ? fileNames.findIndex((item: any) => item === this.activeTableFileName)
        : 0
    const table = tableNames[index]
    const columns = this.previewDataWithTypeSemantic[index].head
    if (this.haveSetDesensitization[table]) {
      columns.forEach((item: any) => {
        maskData.push({
          dataLevelId: this.haveSetDesensitization[table][item.name].masking
            ? this.haveSetDesensitization[table][item.name].dataLevelId
            : null,
          dataMaskingType: this.haveSetDesensitization[table][item.name].masking
            ? this.haveSetDesensitization[table][item.name].dataMaskingType
            : null,
          importColumn: this.haveSetDesensitization[table][item.name]
            .importColumn,
          name: item.name,
          semantic: item.semantic || item.recommendSemantic,
          type: item.type,
        })
      })
    }
    const passData = {
      baseTableConfigVO: {
        data: maskData,
      },
      colData: this.previewData[index].data,
    }
    // 设置脱敏后， 将加密后的数据尽心显示， <表格文件>
    GisDataStore.generateMask(passData).then((response) => {
      this.previewDataWithTypeSemantic[index].head = response.data.result.head
      this.previewDataWithTypeSemantic[index].data = response.data.result.data
    })
  }

  /**
   * 一键是否使用 推断数据类型
   */
  public changeTypeInfer(event: any) {
    this.isDataTypeInfer = event.target.checked
    this.editType(event.target.checked)
  }

  /**
   * 一次性修改所有列的数据类型
   * @param mark 是否使用推断的数据类型
   */
  public editType(mark: boolean) {
    // 上传表格文件预览数据 修改 previewData
    this.previewDataWithTypeSemantic.forEach((table: any) => {
      table.head.forEach((column: any, index: number) => {
        // 推断类型 checkbox 选中， 并且推断语义存在， 使用推断语义， 否则 varchar
        const type: string =
          mark && column.recommendType ? column.recommendType : 'varchar'
        column.type = type
        table.head.splice(index, 1, {
          ...table.head[index],
          type,
        })
      })
    })
  }

  /**
   * 一键切换是否使用推断语义
   * @param event
   */
  public changeSemanticInfer(event: any) {
    this.isDataSemanticInfer = event.target.checked
    this.changePreviewDataSemantic(event.target.checked)
  }

  /**
   * 修改 是否使用推断语义
   * @param mark
   */
  public changePreviewDataSemantic(mark: boolean) {
    this.previewDataWithTypeSemantic.forEach((table: any) => {
      table.head.forEach((column: any, index: number) => {
        const semantic: string =
          mark && column.recommendSemantic ? column.recommendSemantic : 'null'
        column.semantic = semantic
        table.head.splice(index, 1, {
          ...table.head[index],
          semantic,
        })
      })
    })
  }

  /**
   * tab更换当前编辑的上传文件的文件名
   */
  public changeTable(fileName: string) {
    this.activeTableFileName = fileName
    this.getDataWithMask()
  }

  private activeTableFileName: string = '' // 当前表

  // 修改数据列的类型
  public changeColType(value: any) {
    const index = this.previewDataWithTypeSemantic.findIndex(
      (item: any) => item.fileName === this.activeTableFileName
    )
    this.previewDataWithTypeSemantic[index].head[value.index].type = value.type
  }

  /**
   * 语义推断与修改
   */
  public changeSemantic(semanticInfo: { index: number; semantic: string }) {
    const { index, semantic } = semanticInfo
    // 当前激活的表
    const indexCol = this.previewDataWithTypeSemantic.findIndex(
      (item: any) => item.fileName === this.activeTableFileName
    )
    this.previewDataWithTypeSemantic[indexCol].head[index].semantic = semantic
  }

  public handleSubmit() {
    if (this.uploadType === 'table') {
      this.handleTableSubmit()
    } else if (this.uploadType === 'shapefile') {
      const filesNameSuffix: any[] = GisDataStore.fileList.map((file: any) => {
        return file.name.slice(file.name.lastIndexOf('.') + 1)
      })
      const checkingDuplicateFiles: any =
        uniq(filesNameSuffix).length === filesNameSuffix.length
      if (checkingDuplicateFiles) {
        const checkState: boolean =
          intersection(['shp', 'shx', 'dbf'], filesNameSuffix).length >= 3
        if (checkState) {
          this.handleShapefileSubmit()
        } else {
          this.$message.warning('至少上传.dbf、.shp、.shx三个文件')
        }
      } else {
        this.$message.warning('请删除重新上传文件！')
      }
    }
  }

  /**
   * table 提交
   */
  public async handleTableSubmit() {
    const passData = this.dealWriteFileData()
    if (
      !(
        passData.files &&
        passData.files[0] &&
        passData.files[0].data &&
        passData.files[0].data.length > 0
      )
    ) {
      this.$message.error('请确保上传文件包含有效数据')
      this.$emit('clear-update-info')
      return
    }
    this.$emit('update-spin-state', { value: true, message: '上传中' })
    try {
      this.loading = true
      const response = await GisDataStore.writeGisFinalDataset(passData)
      this.loading = false
      // 导入数据不成功的话
      if (response.data.code !== 100) {
        DataStore.setMessageModalOption({
          visible: true,
          message: '导入数据失败',
          tips: `原因：${response.data.message}\n提示：${response.data.tips}`,
        })
        // 数据转化类型成功 处理提交失败
        if (response.data.code !== 40013) {
          this.$message.success('上传失败！')
        }
        // 数据导入成功
      } else if (response.data.code === 100) {
        this.$message.success('上传成功！')
        this.$emit('set-selected-keys', response.data.result.datasetId)
      }
      this.$emit('update-spin-state', { value: false, message: '' })
    } catch (error_) {
      console.error('writeFinalDataset error:', error_)
      this.$message.error('上传失败!')
      this.$emit('update-spin-state', { value: false, message: '' })
    }
  }

  /**
   * shapefile 提交
   */
  public async handleShapefileSubmit() {
    const passData: any = {
      batch: this.batch,
      charset: this.codingType,
      datasetName: this.datasetName,
      importType: 'gis',
      srid: GisDataStore.coordinateSystem,
      files: GisDataStore.fileList.map((file: any) => file.name),
    }
    this.$emit('update-spin-state', { value: true, message: '上传中' })
    try {
      this.loading = true
      const response = await GisDataStore.gisImportData(passData)
      this.loading = false
      if (response.data.code === 100) {
        this.$emit('set-selected-keys', response.data.result.datasetId)
      } else {
        this.$message.error(response.data.message)
      }
      this.$emit('update-spin-state', { value: false, message: '' })
    } catch (error_) {
      console.error('writeFinalDataset error:', error_)
      this.$message.error('上传失败!')
      this.$emit('update-spin-state', { value: false, message: '' })
    }
  }

  /**
   * 处理上传文件的数据 参数， 是否导入脱敏 (use methods: handleSubmit )
   * @author
   */
  public dealWriteFileData() {
    const { haveSetDesensitization } = this // 脱敏 配置
    let gisColConfig = {}
    if (this.tableDataGisType === 'point') {
      gisColConfig =
        this.columnGisType === 'latlng'
          ? {
              latCol: this.latCol,
              lonCol: this.lonCol,
            }
          : {
              regionCol: this.regionCol,
            }
    } else {
      gisColConfig = {
        regionCol: this.regionCol,
      }
    }
    return {
      importType: this.uploadTypeTableFileType,
      applyType: 'gis', // 新增
      name: this.datasetName,
      categoryId: this.gisDataCategory,
      gisConfig: {
        type: this.tableDataGisType,
        ...gisColConfig,
      },
      files: this.previewDataWithTypeSemantic.map((item: any) => {
        return {
          filename: item.fileName,
          firstLineAsFields: this.firstLineAsFields,
          data: item.head.map(
            (column: {
              name: string
              type: string
              semantic?: string
              recommendSemantic: string
            }) => {
              // 某张表 某列的脱敏配置
              const columnSet = haveSetDesensitization[item.name][column.name]
              return {
                name: column.name,
                type: column.type,
                dataLevelId: columnSet.masking ? columnSet.dataLevelId : null,
                dataMaskingType: columnSet.masking
                  ? columnSet.dataMaskingType
                  : null,
                importColumn: columnSet.importColumn,
                semantic: column.semantic ? column.semantic : 'null',
              }
            }
          ),
          sheetName: item.name,
        }
      }),
      charSet: this.codingType,
      firstImport: true,
      srid: GisDataStore.coordinateSystem,
      separate: this.tableSeparate,
      quote: this.tableQuote,
      escape: this.tableEscape,
    }
  }

  // 分隔符号
  private tableSeparate: string = ','
  // 引用符号
  private tableQuote: string = '"'
  // 转义符号
  private tableEscape: string = '"'
}
</script>
<style lang="less" scoped>
/* gis data info */

/* 数据导入设置 */
.import-data-set {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  margin-left: 9px;

  .data-set-column {
    flex-shrink: 0;
    width: 300px;

    &.setting-row {
      .ant-row {
        display: inline-block;
        width: 50%;
      }
    }

    /* 脱敏设置 类型推断 语意推断 */
    .desensitization-set {
      align-items: center;
      display: flex;
      height: 40px;

      .data-setting-button {
        align-items: center;
        display: flex;

        .icon-font {
          margin-top: 4px;
        }
      }

      // DataUploadPage 写了 ant-checkbox display: none;
      /deep/ .ant-checkbox {
        display: inline-block;
      }
    }
  }
}

// 确认取消按钮
.button-container {
  align-items: center;
  display: flex;
  flex-direction: row;
  justify-content: center;
  margin-top: 12px;

  button {
    margin-right: 10px;
  }

  .button {
    background-color: #6973ff;
  }
}
</style>
